package com.gurun.camera.device.model.impl;

import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;

import com.danale.player.SPlayer;
import com.danale.player.content.DAudioRecord;
import com.danale.player.content.UniqueId;
import com.danale.player.entity.ChannelDevice;
import com.danale.player.entity.CloudRecordDevice;
import com.danale.player.entity.LocalRecord;
import com.danale.player.entity.MultiChannelDevice;
import com.danale.player.entity.SdRecordDevice;
import com.danale.player.listener.MediaState;
import com.danale.player.listener.OnConnectListener;
import com.danale.player.listener.OnDoubleClickListener;
import com.danale.player.listener.OnMediaStateChangedListener;
import com.danale.player.listener.OnSingleClickListener;
import com.danale.player.window.ScreenType;
import com.danale.sdk.device.constant.DeviceType;
import com.danale.sdk.platform.cache.DeviceCache;
import com.danale.sdk.platform.cache.UserCache;
import com.danale.sdk.platform.constant.cloud.CloudRecordStorageType;
import com.danale.sdk.platform.constant.device.OnlineType;
import com.danale.sdk.platform.constant.device.ProductType;
import com.danale.sdk.platform.entity.device.Device;
import com.danale.sdk.utils.LogUtil;
import com.danale.sdk.utils.device.DeviceHelper;
import com.gurun.camera.account.activity.AccountUtil;
import com.gurun.camera.device.bean.VideoDevice;
import com.gurun.camera.device.constant.VideoDataType;
import com.gurun.camera.device.model.ControlManager;
import com.gurun.camera.device.util.ConstantValue;
import com.gurun.camera.device.util.FileUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import rx.Observable;
import rx.functions.Func1;

import static com.gurun.camera.device.constant.VideoDataType.ONLINE_IPC;

public class VideoControlManager extends ControlManager implements OnMediaStateChangedListener, OnSingleClickListener, OnDoubleClickListener, OnConnectListener {

    public VideoControlManager(VideoDataType type, SPlayer sPlayer, boolean isCardPlayer){
        this.sPlayer = sPlayer;
        this.isCardPlayer = isCardPlayer;
        List<Device> devices;
        switch (type){
            case ONLINE_IPC:
                devices = filterDevice(DeviceCache.getInstance().getDeviceByProductType(ProductType.IPC,false));
                devices.addAll(filterDevice(DeviceCache.getInstance().getDeviceByProductType(ProductType.DV,false)));
                videoDataType = ONLINE_IPC;
                break;
            case GARAGE:
                devices = filterDevice(DeviceCache.getInstance().getDeviceByProductType(ProductType.VISUAL_GARAGE_DOOR,false));
                videoDataType = ONLINE_IPC;
                break;
            case DOORBELL:
                devices= filterDevice(DeviceCache.getInstance().getDeviceByProductType(ProductType.DOORBELL,false));
                videoDataType = ONLINE_IPC;
                break;
            case IPC_HUB:
                devices = DeviceCache.getInstance().getDeviceByDeviceType(DeviceType.IPC_HUB, false, true);
                videoDataType = ONLINE_IPC;
                break;
            default:
                devices = filterDevice(DeviceCache.getInstance().getDeviceByProductType(ProductType.IPC,false));

                videoDataType = type;
                break;
        }

        videoPlayModel = new VideoPlayerModel(type);
        if (devices != null && devices.size() > 0){
            DeviceHelper.sortVideoDevice(devices, new DeviceHelper.DeviceComparator());
            videoPlayModel.setDevices(devices);
            if (videoDataType == VideoDataType.ONLINE_NVR){
                videoPlayModel.setCurSelectScreen(0);
            }else {
                sPlayer.setSource(devices);
                videoPlayModel.setCurSelectScreen(sPlayer.getCurrentSelectedIndex());
            }
        }
        setListener();

    }

    public void setListener() {
        sPlayer.setOnMediaStateChangedListener(this);
        sPlayer.setOnSingleClickListener(this);
        sPlayer.setOnDoubleClickListener(this);
        sPlayer.setOnConnectListener(this);
    }

    @Override
    public void release() {
        if (uniqueId != null){
            stopRecord();
            stopTalk();
            stopAudio();
            stopVideo(false);
        }
    }

    private boolean prepareData() {
        LinkedList<VideoDevice> devices = videoPlayModel.getDevices();
        if (devices != null && devices.size() > 0){
            switch (videoDataType){
                case ONLINE_IPC:
                    if (sPlayer.getCurrentSelectedIndex() < devices.size()){
                        int currentSelectedIndex = sPlayer.getCurrentSelectedIndex();
                        device = (Device) sPlayer.get(currentSelectedIndex);
                        setCurrentVideoDevice(videoPlayModel.getDeviceMap().get(device.getDeviceId()));
                    }
                    break;
                default:
                    if (device == null){
                        device = new Device();
                    }
                    setCurrentVideoDevice(devices.get(0));
                    break;
            }
        }
        if (currentVideoDevice == null || device == null){
            return false;
        }

        return true;
    }

    @Override
    public void prepare() {
        if (prepareData()){
            if (videoDataType != VideoDataType.RECORD){
                sPlayer.setCardPlay(true);
            }
            switch (videoDataType){
                case DOORBELL:
                case GARAGE:
                case ONLINE_IPC:
                    sPlayer.setCardPlay(true);
                    uniqueId = new UniqueId.DeviceId(id);
                    if (currentVideoDevice.getOnlineType() != OnlineType.ONLINE){
                        return;
                    }
                    break;
                case ONLINE_NVR:
                    DeviceType deviceType = device.getDeviceType();
                    switch (deviceType){
                        case NVR_SPLIT:
                        case DVR_SPLIT:
                            uniqueId = new UniqueId.MultiChannelNumber(multiChannelDevice.getMatrix());
                            sPlayer.setSource(multiChannelDevice);
                            break;
                        default:
                            uniqueId = new UniqueId.ChannelNumber(channels);
                            sPlayer.setSource(channelDevice);
                            break;
                    }
                    break;
                case CLOUD:
                case CLOUD_SINGLE:
                    uniqueId = new UniqueId.CloudId(cloud_id);
                    sPlayer.setSource(cloudRecordDevice);
                    sPlayer.setCloudRecordStorageType(CloudRecordStorageType.FILE_STORAGE);
                    break;
                case DISK:
                    uniqueId = new UniqueId.SdId(sd_id);
                    sPlayer.setSource(sdRecordDevice);
                    break;
                case RECORD:
                    uniqueId = new UniqueId.LocalRecordId(local_id);
                    sPlayer.setSource(localRecord);
                    break;
            }
        }
    }

    @Override
    public void startVideo(final boolean visible) {
        super.startVideo(visible);
        if (prepareData()){
            switch (videoDataType){
                case ONLINE_NVR:
                    if (currentVideoDevice.getOnlineType() == OnlineType.ONLINE){
                        sPlayer.startVideo(uniqueId, visible);

                        DeviceType deviceType = device.getDeviceType();
                        UniqueId uniqueId;
                        switch (deviceType){
                            case NVR_SPLIT:
                            case DVR_SPLIT:
                                uniqueId = new UniqueId.MultiChannelNumber(multiChannelDevice.getMatrix());
                                break;
                            default:
                                uniqueId = new UniqueId.ChannelNumber(channels);
                                break;
                        }
                        sPlayer.cacheIfChannels(uniqueId);
                    }
                    break;
                case RECORD:
                    sPlayer.startVideo(uniqueId, visible);
                    break;
                default:
                    MediaState videoState = currentVideoDevice.getVideoState(currentVideoDevice.getChan_num());
                    if (!id.equals(currentVideoDevice.getDevice_id())
                            || videoState == MediaState.STOPPING
                            || videoState == MediaState.STOPPED
                            || videoState == MediaState.IDLE
                            || videoState == MediaState.TIME_OUT
                            || videoState == MediaState.START_FAIL){
                        sPlayer.startVideo(uniqueId, visible);
                    }
                    break;
            }
        }
    }

    @Override
    public void startVideo(){
        startVideo(true);
    }

    @Override
    public void clickAudio() {
        switch (currentVideoDevice.getAudioState(currentVideoDevice.getChan_num())){
            case RUNNING:
            case STARTED:
                stopAudio();
                break;
            case OTHER_ERROR:
            case START_FAIL:
            case STOPPED:
            case IDLE:
                startAudio();
                break;
        }
    }

    @Override
    public void clickTalk() {
//            if (currentVideoDevice.getDeviceType().contains(ProductType.IPC)){
        if (prepareData()){
            switch (currentVideoDevice.getTalkState(currentVideoDevice.getChan_num())){
                case RUNNING:
                case STARTED:
                    stopTalk();
                    break;
                case STOPPED:
                case IDLE:
                    startTalk();
                    break;

            }
        }
//            }
    }

    @Override
    public void startTalk() {
        if (prepareData()){
            sPlayer.talk(uniqueId);
        }
    }

    @Override
    public void stopTalk() {
        if (prepareData()){
            sPlayer.stopTalk(uniqueId);
        }
    }

    @Override
    public void clickRecord() {
        startTimer();
        if (prepareData()){
            switch (currentVideoDevice.getRecordState(currentVideoDevice.getChan_num())){
                case RUNNING:
                case STARTED:
                    stopRecord();
                    return;
                case STOPPED:
                case IDLE:
                    startRecord();
                    break;
            }
        }
    }

    private void startRecord() {
        String accountName = UserCache.getCache().getUser().getAccountName();
        if (device.getDeviceType() == DeviceType.RING){
            recordFilePath = FileUtils.getRecordFilePathPortraitBell(accountName, device.getAlias(), device.getChannelNum(), ConstantValue.Suffix.MP4);
        }else if (DeviceHelper.isFishDevice(device)){
            recordFilePath = FileUtils.getRecordFilePathPortraitFisher(accountName, device.getDeviceId(), device.getChannelNum(), sPlayer.getCurrConfigText(uniqueId), ConstantValue.Suffix.MP4);
        }else {
            recordFilePath = FileUtils.getRecordFilePath(accountName, device.getAlias(), device.getChannelNum(), ConstantValue.Suffix.MP4);
        }

        sPlayer.videoRecord(uniqueId, recordFilePath);

        capture(getRecordThumbPath(), false, false);
    }

    private String recordFilePath;
    private String getRecordThumbPath(){
        String accountName = UserCache.getCache().getUser().getAccountName();
        return FileUtils.getRecordFileThumbPath(accountName, recordFilePath, ConstantValue.Suffix.MP4);
    }

    @Override
    public void stopVideo() {
        stopVideo(false);
    }

    @Override
    public void stopVideo(boolean closeConnection) {
        super.stopVideo(closeConnection);
        if (currentVideoDevice == null){
            return;
        }
        LogUtil.d("VideoPlayer", "stop " + " id :" + uniqueId.getUniqueId());

        if (videoDataType == VideoDataType.ONLINE_NVR){
            if (currentVideoDevice.getOnlineType() == OnlineType.ONLINE){
                sPlayer.stopVideo(uniqueId, closeConnection);
            }
        }else {
            MediaState videoState = currentVideoDevice.getVideoState(currentVideoDevice.getChan_num());
            if (!id.equals(currentVideoDevice.getDevice_id())
                    || videoState == MediaState.RUNNING
                    || videoState == MediaState.STARTED
                    || videoState == MediaState.STARTING){
            }
            if (sPlayer.getScreenType() == ScreenType.Four){
                sPlayer.stopGroup(closeConnection);
            }else {
                sPlayer.stopVideo(uniqueId, closeConnection);
            }
        }
    }

    @Override
    public void stopVideoData() {
        super.stopVideoData();
        sPlayer.stopVideoPlaying(uniqueId);
    }

    @Override
    public void startAudio() {
        if (prepareData()){
            sPlayer.startAudio(uniqueId);
        }
    }

    @Override
    public void stopAudio() {
        if (prepareData()){
            sPlayer.stopAudio(uniqueId);
        }
    }

    @Override
    public void setIsSilence(boolean isSilence){
        sPlayer.setSilence(isSilence);
    }

    @Override
    public void setRecordCallback(DAudioRecord.RecordCallback callback) {
        super.setRecordCallback(callback);
        sPlayer.setAudioDataCallback(callback);
    }

    @Override
    public void stopRecord() {
        stopTimer();
        sPlayer.stopVideoRecord(uniqueId);
    }

    @Override
    public void changeChannel(int[] channel) {
        super.changeChannel(channel);
        DeviceType deviceType = device.getDeviceType();
        switch (deviceType){
            case DVR_SPLIT:
            case NVR_SPLIT:
                int[][] channels = new int[1][1];
                channels[0][0] = channel[0];
                uniqueId = new UniqueId.MultiChannelNumber(channels);
                break;
            default:
                int[] channel_nvr = channel;
//                channel_nvr[0] = channel;
                uniqueId = new UniqueId.ChannelNumber(channel_nvr);
                break;
        }
        sPlayer.changeChannel(uniqueId);
    }

    @Override
    public void setChannel(int channel){
        DeviceType deviceType = device.getDeviceType();
        switch (deviceType){
            case NVR_SPLIT:
            case DVR_SPLIT:
                int[][] channels_split = new int[1][1];
                channels_split[0][0] = channel;
                uniqueId = new UniqueId.MultiChannelNumber(channels_split);
                break;
            default:
                int[] channels_nvr = new int[1];
                channels_nvr[0] = channel;
                uniqueId = new UniqueId.ChannelNumber(channels_nvr);
                break;
        }
    }

    @Override
    public void pause() {
        super.pause();
        sPlayer.pause(uniqueId);
    }

    @Override
    public void resume() {
        super.resume();
        sPlayer.resume(uniqueId);
    }

    @Override
    public void capture() {
        File file = FileUtils.getSnapshotDir(UserCache.getCache().getUser().getAccountName());
        capture(FileUtils.getSavedScreenShotPath(file, device), false, true);
    }

    private String capturePath;
    void capture(String path, boolean isVideoThumb, boolean isNeedToNotify){
        capturePath = path;
        if (prepareData() && !TextUtils.isEmpty(path)){
            sPlayer.capture(uniqueId, path, isVideoThumb, isNeedToNotify);
        }
    }

    @Override
    public int getCurrentPosition() {
        return sPlayer.getCurrentPosition(uniqueId);
    }

    @Override
    public int getDuration() {
        return sPlayer.getDuration(uniqueId);
    }

    @Override
    public void seekTo(int misc) {
        super.seekTo(misc);
        sPlayer.seekTo(uniqueId, misc);
    }

    @Override
    public void selectSubScreen(String device_id) {

        Device device = (Device) sPlayer.get(sPlayer.getCurrentSelectedIndex());
        UniqueId old_uniqueId = null;
        if (device != null){
            old_uniqueId = new UniqueId.DeviceId(device.getDeviceId());
        }
        id = device_id;
        this.device = DeviceCache.getInstance().getDevice(device_id);
        uniqueId = new UniqueId.DeviceId(id);
        if (sPlayer.isInScreen(uniqueId,true)){
            sPlayer.release(uniqueId, false);
        }
        sPlayer.exchange(old_uniqueId, uniqueId);
    }

    @Override
    public void switchScreenState() {
        if (sPlayer.isIntegrate()){
            stopTalk();
            stopAudio();
            stopRecord();

            sPlayer.split();
            sPlayer.startGroup(sPlayer.calculateGroupIndex(uniqueId));
        }else {
            sPlayer.integrate();
        }
    }

    @Override
    public void initPlay(int width, float factor, ScreenType screenType) {
        super.initPlay(width, factor, screenType);
        sPlayer.setAspectRatio(factor);
        ViewGroup.LayoutParams layoutParams = sPlayer.getLayoutParams();
        layoutParams.width = width;
        layoutParams.height = (int) (width / factor);
        sPlayer.setLayoutParams(layoutParams);
        sPlayer.bindScreen(screenType); //设置屏幕类型
    }

    @Override
    public void setId(String id) {
        super.setId(id);
        device = DeviceCache.getInstance().getDevice(id);
        if (videoDataType == VideoDataType.ONLINE_NVR){
            List<Device> deviceList = new ArrayList<>();
            deviceList.add(device);
//            sPlayer.setSource(deviceList);
            videoPlayModel = new VideoPlayerModel(videoDataType);
            videoPlayModel.setDevices(deviceList);
            channels = new int[4];
            for (int i = 0; i < channels.length && i < 4; i ++){
                channels[i] = i + 1;
            }
            channelDevice = new ChannelDevice(device, channels);
        }
    }

    @Override
    public void updateData(String device_id) {
        super.updateData(device_id);
        device = DeviceCache.getInstance().getDevice(device_id);
        uniqueId = new UniqueId.DeviceId(device_id);
        setCurrentVideoDevice(videoPlayModel.getDeviceMap().get(device_id));
    }

    @Override
    public void setCloudRecordData(CloudRecordDevice cloudDevice) {
        cloudRecordDevice = cloudDevice;
        cloud_id = cloudDevice.getCloudRecordPlayInfos().get(0).getId();
        Device device = cloudDevice.getDevice();
        List<Device> deviceList = new ArrayList<>();
        deviceList.add(device);
        videoPlayModel.setDevices(deviceList);
        currentVideoDevice = videoPlayModel.getDevices().get(0);
    }

    @Override
    public void setSDRecordData(SdRecordDevice sdDevice) {
        super.setSDRecordData(sdDevice);
        sdRecordDevice = sdDevice;
        Device device = sdDevice.getDevice();
        List<Device> deviceList = new ArrayList<>();
        deviceList.add(device);
        videoPlayModel.setDevices(deviceList);
        sd_id = sdDevice.getSdRecords().get(0).getId();
        currentVideoDevice = videoPlayModel.getDevices().get(0);
    }

    @Override
    public void setLocalRecordData(String file_path) {
        super.setLocalRecordData(file_path);
        List<Device> devices = DeviceCache.getInstance().getDeviceByProductType(ProductType.IPC,false);
        if (devices == null || devices.size() == 0){
            device = new Device();
            List<ProductType> productTypes = new ArrayList<>();
            productTypes.add(ProductType.IPC);
            device.setProductTypes(productTypes);
        }else {
            device = devices.get(0);
        }
        videoPlayModel.setDevices(devices);
        id = local_id = file_path + System.currentTimeMillis();
        localRecord = new LocalRecord();
        localRecord.setContext(AccountUtil.getInstance(null).getAppContext());
        localRecord.setFilePath(file_path);
        localRecord.setId(local_id);
    }

    @Override
    public void setMultiChanDevice(MultiChannelDevice device) {
        super.setMultiChanDevice(device);
        multiChannelDevice = device;
    }

    @Override
    public void OnVideoStateChanged(final UniqueId uniqueId, MediaState mediaState) {
        if (currentVideoDevice != null){
            currentVideoDevice.setVideoState(currentVideoDevice.getChan_num(), mediaState);
        }
        if (mediaState == MediaState.RUNNING && !isCardPlayer){
            saveDevThumbnail(uniqueId);
        }
        if (onMediaStateListener != null){
            onMediaStateListener.onVideoStateChange(String.valueOf(uniqueId.getUniqueId()), mediaState);
        }
    }

    /**
     *  视频开启成功之后保存设备的缩略图
     * @param uniqueId
     */
    private void saveDevThumbnail(final UniqueId uniqueId) {

    }

    @Override
    public void OnAudioStateChanged(UniqueId uniqueId, MediaState mediaState) {
        if (currentVideoDevice != null){
            currentVideoDevice.setAudioState(currentVideoDevice.getChan_num(), mediaState);
        }
        if (onMediaStateListener != null){
            onMediaStateListener.onAudioStateChange(mediaState);
        }
    }

    @Override
    public void OnCaptureStateChanged(UniqueId uniqueId, MediaState mediaState) {
        if (onMediaStateListener != null){
            onMediaStateListener.onCaptureStateChange(mediaState, capturePath);
        }
    }

    @Override
    public void OnTalkStateChanged(UniqueId uniqueId, MediaState mediaState) {
        if (currentVideoDevice != null){
            currentVideoDevice.setTalkState(currentVideoDevice.getChan_num(), mediaState);
        }
        if (onMediaStateListener != null){
            onMediaStateListener.onTalkStateChange(mediaState);
        }
    }

    @Override
    public void OnVideoRecordStateChanged(UniqueId uniqueId, MediaState mediaState) {
        if (currentVideoDevice != null){
            currentVideoDevice.setRecordState(currentVideoDevice.getChan_num(), mediaState);
        }
        switch (mediaState){
            case START_FAIL:
            case STOPPED:
            case IDLE:
                if (onMediaStateListener != null){
                    onMediaStateListener.onRecordStateChange(mediaState, 0, recordFilePath);
                }
                stopTimer();
                break;
        }
    }

    @Override
    protected void startTimer() {
        super.startTimer();
    }

    @Override
    public void onDoubleClick(View view) {
        if (onPlayerClickListener != null){
            onPlayerClickListener.onDoubleClick();
        }

        DeviceType deviceType = device.getDeviceType();
        if (!sPlayer.isIntegrate()){
            switch (deviceType){
                case GARAGE_DOOR_OPENER_WITH_CAMERA:
                case RING:
                case NVR:
                case FISH_EYE_IPC:
                case IPC_HUB:
                case IPC:
                    stopRecord();
                    stopTalk();
                    stopAudio();
                    sPlayer.startGroup(sPlayer.calculateGroupIndex(uniqueId));
                    break;
                case NVR_SPLIT:
                case DVR_SPLIT:
                    uniqueId = new UniqueId.MultiChannelNumber(multiChannelDevice.getMatrix());
                    break;
                default:
                    uniqueId = new UniqueId.ChannelNumber(channels);
                    break;
            }
        }else {
            switch (deviceType){
                case GARAGE_DOOR_OPENER_WITH_CAMERA:
                case RING:
                case NVR:
                case FISH_EYE_IPC:
                case IPC_HUB:
                case IPC:
                    List<Object> groups = sPlayer.getGroup(sPlayer.calculateGroupIndex(sPlayer.getCurrentSelectedIndex()));
                    Device selectDev = (Device) sPlayer.get(sPlayer.getCurrentSelectedIndex());
                    for (Object object : groups) {
                        Device device = (Device) object;
                        if (!device.getDeviceId().equals(selectDev.getDeviceId())){
                            sPlayer.stopVideo(new UniqueId.DeviceId(device.getDeviceId()), true);
                        }
                    }
                    break;
                case NVR_SPLIT:
                case DVR_SPLIT:
                    int[][] chans = new int[1][1];
                    chans[0][0] = sPlayer.getSelectedScreenChannel();
                    uniqueId = new UniqueId.MultiChannelNumber(chans);
                    currentVideoDevice.setChan_num(sPlayer.getSelectedScreenChannel());
                    break;
                default:
                    int[] chan = new int[1];
                    chan[0] = sPlayer.getSelectedScreenChannel();
                    uniqueId = new UniqueId.ChannelNumber(chan);
                    currentVideoDevice.setChan_num(sPlayer.getSelectedScreenChannel());
                    break;
            }
        }
    }

    @Override
    public void onSingleClick(View view) {
        if (onPlayerClickListener != null){
            onPlayerClickListener.onSingleClick(id);
        }
    }

    /**
     * 过滤得到填充进播放器的数据
     * @param deviceList
     * @return
     */
    List<Device> filterDevice(List<Device> deviceList){
        final List<Device> devices = new ArrayList<>();
        Observable.from(deviceList)
                .flatMap(new Func1<Device, Observable<?>>() {
                    @Override
                    public Observable<?> call(Device device) {
                        DeviceType deviceType = device.getDeviceType();
                        if (device.getOnlineType() == OnlineType.ONLINE){
                            switch (deviceType){
                                case IPC_HUB:
                                    if (!isCardPlayer){
                                        break;
                                    }
                                case IPC:
                                case DV:
                                case RING:
                                case FISH_EYE_IPC:
                                case GARAGE_DOOR_OPENER_WITH_CAMERA:
                                    devices.add(device);
                                    break;
                            }
                        }
                        return null;
                    }
                }).subscribe();
        return devices;
    }

    @Override
    public void onTimeout(int index) {
    }

    @Override
    public void onRetry(int index) {
        switch (videoDataType){
            case ONLINE_IPC:
                Device device = (Device) sPlayer.get(index);
                sPlayer.startVideo(new UniqueId.DeviceId(device.getDeviceId()));
                break;
            default:
                startVideo();
                break;
        }
    }
}
